<?php

namespace liketp\response;

use liketp\Response;

class Xml extends Response
{
    protected $contentType = 'application/xml';

    public function output($data)
    {
        if ($data instanceof \Closure) {
            $data = $data();
        }
        if (is_array($data) == false) $data = [];
        $data = $this->transDataToXml($data);

        $header = '<?xml version="1.0" encoding="' . $this->charset . '" ?>';

        return $header . PHP_EOL . $this->formatBeauty($data);
    }

    //------------------------------------------------ protected
    protected function formatBeauty(array $items, int $level = 0): string
    {
        $res = '';
        foreach ($items as $v) {
            $res .= $v . PHP_EOL;
        }
        return $res;
    }

    protected function transDataToXml($data)
    {
        $res = [];
        if (is_array($data)) {
            $res = $this->transArrayToXml($data);
        } else if (is_object($data)) {
            $res = $this->transObjectToXml($data);
        }
        return $res;
    }

    protected function transArrayToXml($arr): array
    {
        $items = [];
        foreach ($arr as $k => $v) {
            if (is_array($v)) {
                $items[] = "<$k>";
                $items = array_merge($items, $this->transArrayToXml($v));
                $items[] = "</$k>";
            } else if (is_object($v)) {
                $objName = is_numeric($k) ? '' : $k;
                $items = array_merge($items, $this->transObjectToXml($v, $objName));
            } else {
                $items[] = "<$k>$v</$k>";
            }
        }
        return $items;
    }

    protected function transObjectToXml($obj, $name = ''): array
    {
        $items = [];
        $className = get_class($obj);
        $name = $name ?: ltrim(substr($className, strrpos($className, '\\') ?: 0), '\\');
        $properties = get_object_vars($obj);

        $items[] = "<$name>";
        $items = array_merge($items, $this->transArrayToXml($properties));
        $items[] = "</$name>";

        return $items;
    }
}
